/*
 * @ : Copyright (c) 2021 Phytium Information Technology, Inc.
 *
 * SPDX-License-Identifier: Apache-2.0.
 *
 * @Date: 2021-04-27 15:08:44
 * @LastEditTime: 2021-08-16 14:31:32
 * @Description:  Description of file
 * @Modify History:
 * * * Ver   Who        Date         Changes
 * * ----- ------     --------    --------------------------------------
 */

#ifndef FT_CAN_H
#define FT_CAN_H

#include "ft_types.h"
#include "ft_error_code.h"
#include "parameters.h"

#define FCAN_SUCCESS FT_SUCCESS                                       /* SUCCESS */
#define FCAN_FAILURE FT_MAKE_ERRCODE(ErrCan, ErrBspGeneral, 1)        /* Normal */
#define FCAN_TF_FIFO_ISFULL FT_MAKE_ERRCODE(ErrCan, ErrBspGeneral, 2) /* Timeout */

#define FCAN_HANDLER_SEND 1U  /**< Handler type for frame sending interrupt */
#define FCAN_HANDLER_RECV 2U  /**< Handler type for frame reception interrupt*/
#define FCAN_HANDLER_ERROR 3U /**< Handler type for error interrupt */

#if FT_CAN_USE_CANFD == 1
#define FCAN_DATA_LENGTH 64U
#else
#define FCAN_DATA_LENGTH 8U
#endif

/* CAN payload length and DLC definitions according to ISO 11898-1 */
#define CAN_MAX_DLC 8
#define CAN_MAX_DLEN 8
#define CAN_MAX_CTL 3
#define CAN_SFF_ID_BITS 11
#define CAN_EFF_ID_BITS 29

/* special address description flags for the CAN_ID */
#define CAN_EFF_FLAG 0x80000000U /* EFF/SFF is set in the MSB */
#define CAN_RTR_FLAG 0x40000000U /* remote transmission request */
#define CAN_ERR_FLAG 0x20000000U /* error message frame */

/* valid bits in CAN ID for frame formats */
#define CAN_SFF_MASK 0x000007FFU /* standard frame format (SFF) */
#define CAN_EFF_MASK 0x1FFFFFFFU /* extended frame format (EFF) */
#define CAN_ERR_MASK 0x1FFFFFFFU /* omit EFF, RTR, ERR flags */

/* Frame type */
#define STANDARD_FRAME 0 /* standard frame */
#define EXTEND_FRAME 1   /* extended frame */

/* Bit timing calculate */
#define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */
#define CAN_CALC_SYNC_SEG 1

#define FCAN_CALC_ARB_TIMING 0
#define FCAN_CALC_DATA_TIMING 1

/* Can error status bit mask */
#define FCAN_BUS_ERROR_MASK 1
#define FCAN_PASSIVE_ERROR_MASK 2
#define FCAN_PASSIVE_WARNING_MASK 4
#define FCAN_FIFO_RX_OVERFLOW_MASK 8

/* Can frame select */
#define FCAN_STANDARD_FRAME 0
#define FCAN_EXTENDARD_FRAME 1

/*
 * defined bits for FCanFrame.flags
 *
 * The use of struct FCanFrame implies the Extended Data Length (EDL) bit to
 * be set in the CAN frame bitstream on the wire. The EDL bit switch turns
 * the CAN controllers bitstream processor into the CAN FD mode which creates
 * two new options within the CAN FD frame specification:
 *
 * Bit Rate Switch - to indicate a second bitrate is/was used for the payload
 * Error State Indicator - represents the error state of the transmitting node
 *
 * As the CANFD_ESI bit is internally generated by the transmitting CAN
 * controller only the CANFD_BRS bit is relevant for real CAN controllers when
 * building a CAN FD frame for transmission. Setting the CANFD_ESI bit can make
 * sense for virtual CAN interfaces to test applications with echoed frames.
 */
#define CANFD_BRS 0x02 /* bit rate switch (second bitrate for payload data) */
#define CANFD_ESI 0x04 /* error state indicator of the transmitting node */

typedef void (*FCanirqHandler)(void *args);
typedef void (*FCanErrorHandler)(void *args, u32 error_status, u32 txerr_cnt, u32 rxerr_cnt);

struct FCanFrame
{
    u32 canid;
    u8 candlc;
    u8 flags; /* additional flags for CAN FD */
    u8 data[FCAN_DATA_LENGTH] __attribute__((aligned(8)));
};

struct FCanBittiming
{
    u32 bitrate;      /* Bit-rate in bits/second */
    u32 sample_point; /* Sample point in one-tenth of a percent */
    u32 tq;           /* Time quanta (TQ) in nanoseconds */
    u32 prop_seg;     /* Propagation segment in TQs */
    u32 phase_seg1;   /* Phase buffer segment 1 in TQs */
    u32 phase_seg2;   /* Phase buffer segment 2 in TQs */
    u32 sjw;          /* Synchronisation jump width in TQs */
    u32 brp;          /* Bit-rate prescaler */
};

typedef struct
{
    u32 instanceid;   /* Id of device */
    u32 base_address; /* Can base Address */
    u32 irq_num;
    u32 baudrate;
    u32 txfifo_deepth; /* The depth of the full frame , */
} FCanConfig;

typedef struct
{
    FCanConfig config;
    u32 is_ready;  /* Device is initialized and ready */
    u32 use_canfd; /* The CANFD function was enabled */

    FCanirqHandler send_handler;
    void *send_ref;

    FCanirqHandler recv_handler;
    void *recv_ref;

    FCanErrorHandler error_handler;
    void *error_ref;

} FCan;

FCanConfig *FCanLookupConfig(u32 InstanceId);

/**
 * @name: FCanCfgInitialize
 * @msg:  This function initializes a Can instance/driver.
 * @in param instance_p:    instance_p is a pointer to the FCan instance.
 * @in param Config_p: Config_p points to the FCan device configuration structure.
 * @return {*}
 */
ft_error_t FCanCfgInitialize(FCan *instance_p, FCanConfig *Config_p);

/**
 * @name: FCanSetHandler
 * @msg:  This routine installs an asynchronous callback function for the given
 * @inout param instance_p: instance_p is a pointer to the FCan instance.
 * @in param HandlerType:  specifies which handler is to be attached.
 * @in param IrqCallBackFunc: IrqCallBackFunc is the address of the callback function.
 * @in param IrqCallBackRef: IrqCallBackRef is a user data item that will be passed to the
 *      callback function when it is invoked.
 * @return {*}
 * @param {FCan} *instance_p     is a pointer to the FCan instance.
 * @param {u32} handler_type  specifies which handler is to be attached.
 * @param {FCanirqHandler} *IrqCallBackFunc  is the address of the callback function.
 * @param {void} *IrqCallBackRef is a user data item that will be passed to the
 *		callback function when it is invoked.
 */
ft_error_t FCanSetHandler(FCan *instance_p, u32 handler_type, void *irq_callback_func, void *irq_callback_ref);

/**
 * @name: FCan_SetTiming
 * @msg:  This routine sets Bit time
 * @param {FCan} *instance_p is a pointer to the FCan instance.
 * @inout param: 
 * @out param: 
 * @return {*}
 */
ft_error_t FCanSetTiming(FCan *instance_p,
                         struct FCanBittiming *bittiming_arb_p,
                         struct FCanBittiming *bittiming_data_p);

/**
 * @name:   FCanIntrHandler
 * @msg:    This routine is the interrupt handler for the CAN driver.
 * @param {void} *instance_ptr is a pointer to the FCan instance.
 * @return {*}
 */
void FCanIntrHandler(void *instance_ptr);

/**
 * @name: FCanCalcBittiming
 * @msg:  This routine calculate Bit time  
 * @param {structFCanBittiming} *bt_p is is a structure that contains the CAN baud rate configuration parameter , The user needs to fill in the bitrate first 
 * @param {u32} TimingTagetSelect specifies which target is to be selected. followed by FCAN_CALC_DATA_TIMING or FCAN_CALC_ARB_TIMING
 * @return {*}
 */
ft_error_t FCanCalcBittiming(struct FCanBittiming *bt_p, u32 TimingTagetSelect);

/**
 * @name: FCanRecv
 * @msg: This function receives a CAN Frame.
 * @param {FCan} *instance_p is a pointer to the FCan instance.
 * @param {structFCanFrame} *frame_p  is a pointer to a 32-bit aligned buffer where the CAN
 *		frame to be written.
 * @return {u32} FCAN_SUCCESS is recive a right frame
 *               FCAN_FAILURE is no frame to be received from the FIFO
 */
u32 FCanRecv(FCan *instance_p, struct FCanFrame *frame_p);

/**
 * @name: FCanSend
 * @msg: This function sends a CAN Frame
 * @param {FCan} *instance_p is a pointer to the FCan instance.
 * @param {structFCanFrame} *frame_p is a pointer to a 32-bit aligned buffer containing the
 *		CAN frame to be sent.
 * @return {*}
 */
u32 FCanSend(FCan *instance_p, struct FCanFrame *frame_p);

/**
 * @name: FCanEnable
 * @msg:  This function enable the can module
 * @param {FCan} *instance_p is a pointer to the FCan instance.
 * @return {*}
 */
void FCanEnable(FCan *instance_p);

/**
 * @name: FCanDisable
 * @msg:  This function Disable the can module
 * @param {FCan} *instance_p is a pointer to the FCan instance.
 * @return {*}
 */
void FCanDisable(FCan *instance_p);

/**
 * @name: FCanGetErrorCnt
 * @msg:  This function reads Receive and Transmit error counters.
 * @param {FCan} *instance_p is a pointer to the FCan instance.
 * @param {u32} *txerr will contain Transmit Error Counter value after
 *		this function returns.
 * @param {u32} *rxerr will contain Receive Error Counter value after this
 *		function returns.
 * @return {*}
 */
void FCanGetErrorCnt(FCan *instance_p, u32 *txerr, u32 *rxerr);

ft_error_t FCanIdMaskFilterSet(FCan *instance_p, u32 filter_index, u32 frame_type, u32 id, u32 mask);
void FCanIdMaskFilterEnable(FCan *instance_p);
void FCanIdMaskFilterDisable(FCan *instance_p);
#endif // !FT_CAN_H
